package kydlp_doctotext

import (
	"os"
	"strings"

	"gitee.com/guoliben/kydlp-doctotext/3rdparty/fileidentify"
	"gitee.com/guoliben/kydlp-doctotext/compressextractor"
	"gitee.com/guoliben/kydlp-doctotext/docextractor"
	"gitee.com/guoliben/kydlp-doctotext/extractor_interface"
	"gitee.com/guoliben/kydlp-doctotext/imageextractor"
	"gitee.com/guoliben/kydlp-doctotext/utils/ctrlledprint"
)

type ExtractConfig struct {
	MaxUncompressDepth int
	OcrEngineSwitch bool
}

func Init() error {
	config := ExtractConfig{
		MaxUncompressDepth: 9,
		OcrEngineSwitch: false,
	}
	ctrlledprint.Init()

	err := docextractor.Init()
	if err != nil {
		return err
	}
	err = compressextractor.Init(config.MaxUncompressDepth)
	if err != nil {
		return err
	}
	return imageextractor.Init(config.OcrEngineSwitch)
}

func Destroy() {
	docextractor.Destroy()
	imageextractor.Destroy()
}

func isTargetFile(path string) bool {
	info, err := os.Stat(path)

	if err != nil {
		ctrlledprint.Println("获取文件状态信息失败:", err)
		return false
	}
	if (info.Mode() & os.ModeSymlink) != 0 {
		ctrlledprint.Println("跳过链接文件:", path)
		return false
	}
	if (info.Mode() & os.ModeNamedPipe) != 0 {
		ctrlledprint.Println("跳过命名管道文件:", path)
		return false
	}
	if (info.Mode() & os.ModeSocket) != 0 {
		ctrlledprint.Println("跳过本地套接字文件:", path)
		return false
	}

	return true
}

func ExtractTextFromFile(path string, size int64) ([]byte, string) {
	if !isTargetFile(path) { return nil, "" }

	filetype, _, _, _ := fileidentify.IdentifyFromFile(path)

	switch strings.TrimSpace(filetype) {

	case fileidentify.DocTypeText, fileidentify.DocTypeHtml, fileidentify.DocTypeXml, fileidentify.DocTypeJson,
		fileidentify.DocTypePdf,
		fileidentify.DocTypeMsDoc, fileidentify.DocTypeMsDocx,
		fileidentify.DocTypeMsXls, fileidentify.DocTypeMsXlsx,
		fileidentify.DocTypeMsPpt, fileidentify.DocTypeMsPptx:
		return docextractor.TextExtractorFactory(filetype).GetTextFromFile(path, size, filetype, 1)

	case fileidentify.CompressTypeTar, fileidentify.CompressTypeGzOrTarGz, fileidentify.CompressTypeZip,
		fileidentify.CompressTypeRar, fileidentify.CompressTypeRarAliase1, fileidentify.CompressTypeRarAliase2,
		fileidentify.CompressType7z:
		return compressextractor.TextExtractorFactory(filetype).GetTextFromFile(path, size, filetype, 1)

	case fileidentify.ImageTypeBmp, fileidentify.ImageTypeJpeg, fileidentify.ImageTypePng,
		fileidentify.ImageTypeGif, fileidentify.ImageTypeTiff:
		return imageextractor.TextExtractorFactory(filetype).GetTextFromFile(path, size, filetype, 1)

	default:
		return extractor_interface.UnknownType{}.GetTextFromFile(path, size, filetype, 1)
	}
}

func ExtractTextFromBuffer(path string, data []byte, size int64) ([]byte, string) {
	filetype, _, _, _ := fileidentify.IdentifyFromBuffer(data)

	switch strings.TrimSpace(filetype) {

	case fileidentify.DocTypeText, fileidentify.DocTypeHtml, fileidentify.DocTypeXml, fileidentify.DocTypeJson,
		fileidentify.DocTypePdf,
		fileidentify.DocTypeMsDoc, fileidentify.DocTypeMsDocx,
		fileidentify.DocTypeMsXls, fileidentify.DocTypeMsXlsx,
		fileidentify.DocTypeMsPpt, fileidentify.DocTypeMsPptx:
		return docextractor.TextExtractorFactory(filetype).GetTextFromBuffer(path, data, size, filetype, 1)

	case fileidentify.CompressTypeTar, fileidentify.CompressTypeGzOrTarGz, fileidentify.CompressTypeZip,
		fileidentify.CompressTypeRar, fileidentify.CompressTypeRarAliase1, fileidentify.CompressTypeRarAliase2,
		fileidentify.CompressType7z:
		return compressextractor.TextExtractorFactory(filetype).GetTextFromBuffer(path, data, size, filetype, 1)

	case fileidentify.ImageTypeBmp, fileidentify.ImageTypeJpeg, fileidentify.ImageTypePng,
		fileidentify.ImageTypeGif, fileidentify.ImageTypeTiff:
		return imageextractor.TextExtractorFactory(filetype).GetTextFromBuffer(path, data, size, filetype, 1)

	default:
		return extractor_interface.UnknownType{}.GetTextFromBuffer(path, data, size, filetype, 1)
	}
}

func ExtractTextFromFileWithCallback(path string, size int64, callback extractor_interface.OnTextDetectHandler, context interface{}) (int, []byte, string) {
	if !isTargetFile(path) { return 0, nil, "" }

	filetype, _, _, _ := fileidentify.IdentifyFromFile(path)

	switch strings.TrimSpace(filetype) {

	case fileidentify.DocTypeText, fileidentify.DocTypeHtml, fileidentify.DocTypeXml, fileidentify.DocTypeJson,
		fileidentify.DocTypePdf,
		fileidentify.DocTypeMsDoc, fileidentify.DocTypeMsDocx,
		fileidentify.DocTypeMsXls, fileidentify.DocTypeMsXlsx,
		fileidentify.DocTypeMsPpt, fileidentify.DocTypeMsPptx:
		return docextractor.TextExtractorFactory(filetype).GetTextFromFileWithCallback(path, size, filetype, 1, callback, context)

	case fileidentify.CompressTypeTar, fileidentify.CompressTypeGzOrTarGz, fileidentify.CompressTypeZip,
		fileidentify.CompressTypeRar, fileidentify.CompressTypeRarAliase1, fileidentify.CompressTypeRarAliase2,
		fileidentify.CompressType7z:
		return compressextractor.TextExtractorFactory(filetype).GetTextFromFileWithCallback(path, size, filetype, 1, callback, context)

	case fileidentify.ImageTypeBmp, fileidentify.ImageTypeJpeg, fileidentify.ImageTypePng,
		fileidentify.ImageTypeGif, fileidentify.ImageTypeTiff:
		return imageextractor.TextExtractorFactory(filetype).GetTextFromFileWithCallback(path, size, filetype, 1, callback, context)

	default:
		return extractor_interface.UnknownType{}.GetTextFromFileWithCallback(path, size, filetype, 1, callback, context)
	}
}

func ExtractTextFromBufferWithCallback(path string, data []byte, size int64, callback extractor_interface.OnTextDetectHandler, context interface{}) (int, []byte, string) {
	filetype, _, _, _ := fileidentify.IdentifyFromBuffer(data)

	switch strings.TrimSpace(filetype) {

	case fileidentify.DocTypeText, fileidentify.DocTypeHtml, fileidentify.DocTypeXml, fileidentify.DocTypeJson,
		fileidentify.DocTypePdf,
		fileidentify.DocTypeMsDoc, fileidentify.DocTypeMsDocx,
		fileidentify.DocTypeMsXls, fileidentify.DocTypeMsXlsx,
		fileidentify.DocTypeMsPpt, fileidentify.DocTypeMsPptx:
		return docextractor.TextExtractorFactory(filetype).GetTextFromBufferWithCallback(path, data, size, filetype, 1, callback, context)

	case fileidentify.CompressTypeTar, fileidentify.CompressTypeGzOrTarGz, fileidentify.CompressTypeZip,
		fileidentify.CompressTypeRar, fileidentify.CompressTypeRarAliase1, fileidentify.CompressTypeRarAliase2,
		fileidentify.CompressType7z:
		return compressextractor.TextExtractorFactory(filetype).GetTextFromBufferWithCallback(path, data, size, filetype, 1, callback, context)

	case fileidentify.ImageTypeBmp, fileidentify.ImageTypeJpeg, fileidentify.ImageTypePng,
		fileidentify.ImageTypeGif, fileidentify.ImageTypeTiff:
		return imageextractor.TextExtractorFactory(filetype).GetTextFromBufferWithCallback(path, data, size, filetype, 1, callback, context)

	default:
		return extractor_interface.UnknownType{}.GetTextFromBufferWithCallback(path, data, size, filetype, 1, callback, context)
	}
}

func ExtractStringTextFromFile(path string, size int64) (string, string) {
	if !isTargetFile(path) { return "", "" }

	filetype, _, _, _ := fileidentify.IdentifyFromFile(path)

	switch strings.TrimSpace(filetype) {

	case fileidentify.DocTypeText, fileidentify.DocTypeHtml, fileidentify.DocTypeXml, fileidentify.DocTypeJson,
		fileidentify.DocTypePdf,
		fileidentify.DocTypeMsDoc, fileidentify.DocTypeMsDocx,
		fileidentify.DocTypeMsXls, fileidentify.DocTypeMsXlsx,
		fileidentify.DocTypeMsPpt, fileidentify.DocTypeMsPptx:
		return docextractor.TextExtractorFactory(filetype).GetStringTextFromFile(path, size, filetype, 1)

	case fileidentify.CompressTypeTar, fileidentify.CompressTypeGzOrTarGz, fileidentify.CompressTypeZip,
		fileidentify.CompressTypeRar, fileidentify.CompressTypeRarAliase1, fileidentify.CompressTypeRarAliase2,
		fileidentify.CompressType7z:
		return compressextractor.TextExtractorFactory(filetype).GetStringTextFromFile(path, size, filetype, 1)

	case fileidentify.ImageTypeBmp, fileidentify.ImageTypeJpeg, fileidentify.ImageTypePng,
		fileidentify.ImageTypeGif, fileidentify.ImageTypeTiff:
		return imageextractor.TextExtractorFactory(filetype).GetStringTextFromFile(path, size, filetype, 1)

	default:
		return extractor_interface.UnknownType{}.GetStringTextFromFile(path, size, filetype, 1)
	}
}

func ExtractStringTextFromBuffer(path string, data []byte, size int64) (string, string) {
	filetype, _, _, _ := fileidentify.IdentifyFromBuffer(data)

	switch strings.TrimSpace(filetype) {

	case fileidentify.DocTypeText, fileidentify.DocTypeHtml, fileidentify.DocTypeXml, fileidentify.DocTypeJson,
		fileidentify.DocTypePdf,
		fileidentify.DocTypeMsDoc, fileidentify.DocTypeMsDocx,
		fileidentify.DocTypeMsXls, fileidentify.DocTypeMsXlsx,
		fileidentify.DocTypeMsPpt, fileidentify.DocTypeMsPptx:
		return docextractor.TextExtractorFactory(filetype).GetStringTextFromBuffer(path, data, size, filetype, 1)

	case fileidentify.CompressTypeTar, fileidentify.CompressTypeGzOrTarGz, fileidentify.CompressTypeZip,
		fileidentify.CompressTypeRar, fileidentify.CompressTypeRarAliase1, fileidentify.CompressTypeRarAliase2,
		fileidentify.CompressType7z:
		return compressextractor.TextExtractorFactory(filetype).GetStringTextFromBuffer(path, data, size, filetype, 1)

	case fileidentify.ImageTypeBmp, fileidentify.ImageTypeJpeg, fileidentify.ImageTypePng,
		fileidentify.ImageTypeGif, fileidentify.ImageTypeTiff:
		return imageextractor.TextExtractorFactory(filetype).GetStringTextFromBuffer(path, data, size, filetype, 1)

	default:
		return extractor_interface.UnknownType{}.GetStringTextFromBuffer(path, data, size, filetype, 1)
	}
}

func ExtractStringTextFromFileWithCallback(path string, size int64, callback extractor_interface.OnStringTextDetectHandler, context interface{}) (int, string, string) {
	if !isTargetFile(path) { return 0, "", "" }

	filetype, _, _, _ := fileidentify.IdentifyFromFile(path)

	switch strings.TrimSpace(filetype) {

	case fileidentify.DocTypeText, fileidentify.DocTypeHtml, fileidentify.DocTypeXml, fileidentify.DocTypeJson,
		fileidentify.DocTypePdf,
		fileidentify.DocTypeMsDoc, fileidentify.DocTypeMsDocx,
		fileidentify.DocTypeMsXls, fileidentify.DocTypeMsXlsx,
		fileidentify.DocTypeMsPpt, fileidentify.DocTypeMsPptx:
		return docextractor.TextExtractorFactory(filetype).GetStringTextFromFileWithCallback(path, size, filetype, 1, callback, context)

	case fileidentify.CompressTypeTar, fileidentify.CompressTypeGzOrTarGz, fileidentify.CompressTypeZip,
		fileidentify.CompressTypeRar, fileidentify.CompressTypeRarAliase1, fileidentify.CompressTypeRarAliase2,
		fileidentify.CompressType7z:
		return compressextractor.TextExtractorFactory(filetype).GetStringTextFromFileWithCallback(path, size, filetype, 1, callback, context)

	case fileidentify.ImageTypeBmp, fileidentify.ImageTypeJpeg, fileidentify.ImageTypePng,
		fileidentify.ImageTypeGif, fileidentify.ImageTypeTiff:
		return imageextractor.TextExtractorFactory(filetype).GetStringTextFromFileWithCallback(path, size, filetype, 1, callback, context)

	default:
		return extractor_interface.UnknownType{}.GetStringTextFromFileWithCallback(path, size, filetype, 1, callback, context)
	}
}

func ExtractStringTextFromBufferWithCallback(path string, data []byte, size int64, callback extractor_interface.OnStringTextDetectHandler, context interface{}) (int, string, string) {
	filetype, _, _, _ := fileidentify.IdentifyFromBuffer(data)

	switch strings.TrimSpace(filetype) {

	case fileidentify.DocTypeText, fileidentify.DocTypeHtml, fileidentify.DocTypeXml, fileidentify.DocTypeJson,
		fileidentify.DocTypePdf,
		fileidentify.DocTypeMsDoc, fileidentify.DocTypeMsDocx,
		fileidentify.DocTypeMsXls, fileidentify.DocTypeMsXlsx,
		fileidentify.DocTypeMsPpt, fileidentify.DocTypeMsPptx:
		return docextractor.TextExtractorFactory(filetype).GetStringTextFromBufferWithCallback(path, data, size, filetype, 1, callback, context)

	case fileidentify.CompressTypeTar, fileidentify.CompressTypeGzOrTarGz, fileidentify.CompressTypeZip,
		fileidentify.CompressTypeRar, fileidentify.CompressTypeRarAliase1, fileidentify.CompressTypeRarAliase2,
		fileidentify.CompressType7z:
		return compressextractor.TextExtractorFactory(filetype).GetStringTextFromBufferWithCallback(path, data, size, filetype, 1, callback, context)

	case fileidentify.ImageTypeBmp, fileidentify.ImageTypeJpeg, fileidentify.ImageTypePng,
		fileidentify.ImageTypeGif, fileidentify.ImageTypeTiff:
		return imageextractor.TextExtractorFactory(filetype).GetStringTextFromBufferWithCallback(path, data, size, filetype, 1, callback, context)

	default:
		return extractor_interface.UnknownType{}.GetStringTextFromBufferWithCallback(path, data, size, filetype, 1, callback, context)
	}
}

func BlockUntilOcrDone() {
	imageextractor.BlockUntilOcrDone()
}

func CloseChanAfterOcrDone() {
	imageextractor.CloseChanAfterOcrDone()
}

func GetAndPrintAllOcrResult() {
	imageextractor.GetAndPrintAllOcrResult()
}

func GetOcrResult() (interface{}, string, int64, string, string, string) {
	return imageextractor.GetOcrResult()
}

func LoopGetAndProcessOcrResult(callback extractor_interface.OnStringTextDetectHandler) {
	for {
		context, path, size, filetype, text, elapsed := GetOcrResult()

		length := len(text)

		if len(path) == 0 && size == 0 && length == 0 {
			ctrlledprint.Println("\n所有图片OCR任务已完成!")
			return
		} else {
			ctrlledprint.Println("\nOCR异步并发结果:")
			ctrlledprint.Println("文件路径:", path)
			ctrlledprint.Println("文件大小:", size, "bytes")
			ctrlledprint.Println("OCR耗时 :", elapsed)

			if callback != nil {
				retcode, _ := callback(path, size, filetype, text, int64(length), context)
				if retcode != 0 {
					break
				}
			}
		}
	}
}
